<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <!-- 引入axios -->
    <!-- <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script> -->
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.0.2/css/bootstrap.min.css" rel="stylesheet">
    <title>axios源码学习</title>
    <style>
        * {
            margin: 0;
            padding: 0
        }

        .container {
            margin-top: 20px;
        }
    </style>
</head>

<body>
    <div class="container">
        <button class="btn btn-primary">发生GET请求 </button>
        <button class="btn btn-danger">取消请求 </button>
        <hr />
        <h4>数据回显</h4>
        <p id="content"></p>
    </div>
    <script>
        const btn_group = document.querySelectorAll('button')
        const content = document.getElementById('content')
        // 创建一个Axios构造函数
        const Axios = function () {
            this.defaults = {
                name: "Axios",
            };
            this.interceptors = {
                request: new InterceptorManager(),
                response: new InterceptorManager()
            }
        }

        function InterceptorManager() {
            this.handlers = []
        }
        InterceptorManager.prototype.use = function use(fulfilled, rejected) {
            this.handlers.push({
                fulfilled,
                rejected
            });
        };
        // 创建CancelToken构造函数
        function CancelToken(fn) {
            let resolvePromise
            this.promise = new Promise((resolve, reject) => {
                resolvePromise = resolve
            })
            fn(() => {
                // 执行resolvePromise函数，其实等于执行了CancelToken.promise.resolve()
                resolvePromise()
            })
        }
        Axios.prototype.request = function (config) {
            // 创建一个promise对象
            let promise = Promise.resolve(config)
            // 创建一个数组
            const chains = [dispatchRequest, undefined]
            this.interceptors.request.handlers.forEach(item => {
                chains.unshift(item.fulfilled, item.rejected)
            })
            this.interceptors.response.handlers.forEach(item => {
                chains.push(item.fulfilled, item.rejected)
            })
            // 调用.then回调
            while (chains.length) {
                promise = promise.then(chains.shift(), chains.shift())
            }
            return promise;
        }

        function dispatchRequest(config) {
            // 调用适配器发送请求
            return xhrAdapter(config).then(response => {
                return response
            }, error => {
                throw error;
            })

        }
        function xhrAdapter(config) {
            return new Promise((resolve, reject) => {
                // 发送Ajax请求
                let xhr = new XMLHttpRequest()
                // 初始化
                xhr.open(config.method, config.url)
                // 发送
                xhr.send()
                xhr.onreadystatechange = () => {
                    //判断成功条件
                    if (xhr.readyState === 4) {
                        if (xhr.status >= 200 && xhr.status < 300) {
                            //成功状态
                            const response = {
                                data: xhr.response,
                                status: xhr.status,
                                statusText: xhr.statusText,
                                headers: xhr.getAllResponseHeaders(),
                                config: config,
                                request: xhr
                            }
                            resolve(response)
                        } else {
                            //失败状态
                            reject(new Error('请求失败'))
                        }
                    }
                }
                if (config.cancelToken) {
                    config.cancelToken.promise.then((value) => {
                        xhr.abort()
                    })
                }

            })

        }

        function createAxios(config) {
            let context = new Axios()
            let instance = function (config) {
                return Axios.prototype.request.apply(context, [config])
            }
            Object.assign(instance, Axios.prototype, context)
            return instance
        }
        let cancel = null
        let cancelToken = new CancelToken(function (c) {
            cancel = c
        })
        //    使用axios
        let axios = createAxios()
        // 使用拦截器
        axios.interceptors.request.use((config) => {
            // 在发送请求之前做些什么
            console.log(`请求拦截器1号`, config)
            return config;
        }, (error) => {
            // 对请求错误做些什么
            return Promise.reject(error);
        })

        axios.interceptors.response.use((response) => {
            console.log(`响应拦截器1号`, response)
            return response
        }, (error) => {
            return Promise.reject(error);
        })

        btn_group[0].onclick = function () {
            axios({
                method: 'get',
                url: 'http://localhost:3000/posts',
                cancelToken: cancelToken
            }).then((response) => {
                content.innerHTML = JSON.stringify(response)
            }).catch((thrown) => {
                console.log(`thrown`, thrown)
            });


        }
        btn_group[1].onclick = function () {
            cancel()
        }

    </script>
</body>

</html>